package ru.papergames.battleserver.telnet;

import javolution.util.FastMap;
import ru.papergames.battleserver.BattleThreadPoolManager;
import ru.papergames.battleserver.Shutdown;
import ru.papergames.battleserver.model.AbstractPaperGameUser;
import ru.papergames.battleserver.model.UsersManager;
import ru.papergames.battleserver.model.battle.AbstractBattle;
import ru.papergames.battleserver.model.battle.BattleManager;
import ru.papergames.battleserver.model.battle.BattlePlayer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.List;

/**
 * @author: atroshanin
 * Date: 22.04.2010
 * Time: 22:45:03
 */
public class BattleTelnetSession extends Thread {

    private BattleTelnetServer telnetServer;
    private int sessionId;

    private Socket _cSocket;

    private PrintWriter _print;
    private BufferedReader _read;

    private int _uptime;

    private boolean started;

    private void telnetOutput(int type, String text) {
        //only print output if the message is rejected
        if (type == 5) System.out.println("TELNET | " + text);
    }

    private boolean isValidIP(Socket client, String[] trustedHosts) {
        // TODO: change this value to false in prod.
        boolean result = true;
        InetAddress ClientIP = client.getInetAddress();

        // convert IP to String, and compare with list
        String clientStringIP = ClientIP.getHostAddress();

        telnetOutput(1, "Connection from: " + clientStringIP);

        // read and loop thru list of IPs, compare with newIP
        try {
            // compare
            for (String ip : trustedHosts) {
                String ipToCompare = InetAddress.getByName(ip).getHostAddress();
                if (clientStringIP.equals(ipToCompare)) {
                    result = true;
                    break;
                }
            }
        } catch (IOException e) {
            telnetOutput(1, "Error: " + e);
        }

        return result;
    }

    public BattleTelnetSession(BattleTelnetServer telnetServer, Socket client, int uptime, String statusPW, String[] trustedHosts, int id) throws IOException {
        this.telnetServer = telnetServer;
        this.sessionId = id;
        _cSocket = client;
        _uptime = uptime;

        String lineSep = System.getProperty("line.separator");
        System.setProperty("line.separator", "\n\r");
        _print = new PrintWriter(_cSocket.getOutputStream());
        _read = new BufferedReader(new InputStreamReader(_cSocket.getInputStream()));
        System.setProperty("line.separator", lineSep);

        if (isValidIP(client, trustedHosts)) {
            telnetOutput(1, client.getInetAddress().getHostAddress() + " accepted.");
            _print.println("Welcome To The Oside messaging server Telnet Session.");
            _print.println("Please Insert Your Password!");
            _print.print("Password: ");
            _print.flush();
            String tmpLine = _read.readLine();
            if (tmpLine == null) {
                _print.println("Error.");
                _print.println("Disconnected...");
                _print.flush();
                _cSocket.close();
            } else if (tmpLine.compareTo(statusPW) != 0) {
                _print.println("Incorrect Password!");
                _print.println("Disconnected...");
                _print.flush();
                _cSocket.close();
            } else {
                _print.println("Password Correct!");
                _print.println("[OSIDE]");
                _print.print("");
                _print.flush();
                start();
                started = true;
            }
        } else {
            telnetOutput(5, "Connection attempt from " + client.getInetAddress().getHostAddress() + " rejected.");
            _cSocket.close();
        }
    }

    public void run() {
        String _usrCommand = "";
        try {
            while (_usrCommand.compareTo("quit") != 0 && _usrCommand.compareTo("exit") != 0) {
                _usrCommand = _read.readLine();
                if (_usrCommand == null) {
                    _cSocket.close();
                    break;
                }
                if (_usrCommand.equals("help")) {
                    _print.println("The following is a list of all available commands: ");
                    _print.println("help                - shows this help.");
                    _print.println("status              - displays basic server statistics.");
                    _print.println("online              - prints all online players.");
                    _print.println("perf                - shows server performance statistics.");
                    _print.println("purge               - removes finished threads from thread pools.");
                    _print.println("battles             - list of battles in the game and theirs statuses.");
                    _print.println("announce <text>     - announces <text> in game.");
                    _print.println("msg <nick> <text>   - Sends a whisper to char <nick> with <text>.");
                    _print.println("gmchat <text>       - Sends a message to all GMs with <text>.");
                    _print.println("gmlist              - lists all gms online.");
                    _print.println("kick                - kick player <name> from server.");
                    _print.println("shutdown <time>     - shuts down server in <time> seconds.");
                    _print.println("restart <time>      - restarts down server in <time> seconds.");
                    _print.println("abort               - aborts shutdown/restart.");
                    _print.println("debug <cmd>         - executes the debug command (see 'help debug').");
                    _print.println("gamesync            - writes txt db injects for game.");
                    _print.println("give <player> <itemid> <amount>");
                    _print.println("reload <module>");
                    _print.println("battleRooms         - show all battle rooms");
                    _print.println("saveRoom            - saves rooms messages");
                    _print.println("quit                - closes telnet session.");
                    _print.flush();
                } else if (_usrCommand.equals("help debug")) {
                    _print.println("The following is a list of all available debug commands: ");
                    _print.println("PacketTP            - prints info about the General Packet ThreadPool");
                    _print.println("IOPacketTP          - prints info about the I/O Packet ThreadPool");
                    _print.println("GeneralTP           - prints info about the General ThreadPool");
                    _print.println("BattleTP            - prints info about the Battle ThreadPool");
                } else if (_usrCommand.equals("status")) {
                    _print.println("status - response");
                    _print.flush();
                } else if (_usrCommand.equals("online")) {
                    _print.println("online - response");
                    _print.flush();
/*
                    _print.println("Players online (" + World.getInstance().getAllPlayersCount() + "): ");
                    for (PcInstance player : World.getInstance().getAllPlayers()) {
                        if (player != null) {
                            String message = "  " + player.getName();
                            message += player.getTown() == null ? "" : ", town: " + player.getTown().getName();
                            message += player.isInBattle() ? ", in battle " + player.getBattle().getObjectId() : "";
                            _print.println(message);
                        }
                    }
*/
                } else if (_usrCommand.equals("perf")) {
                    for (String line : BattleThreadPoolManager.getInstance().getStats()) {
                        _print.println(line);
                    }
                    _print.flush();
                } else if (_usrCommand.equals("purge")) {
                    BattleThreadPoolManager.getInstance().purge();
                    _print.println("STATUS OF THREAD POOLS AFTER PURGE COMMAND:");
                    _print.println("");
                    for (String line : BattleThreadPoolManager.getInstance().getStats()) {
                        _print.println(line);
                    }
                    _print.flush();
                } else if (_usrCommand.startsWith("shutdown")) {
                    int val = 1;
                    try {
                        val = Integer.parseInt(_usrCommand.substring(9));
                    } catch (Exception e) {
                        // skip it...
                    }
                    _print.println("Server Will Shutdown In " + val + " Seconds!");
                    _print.println("Type \"abort\" To Abort Shutdown!");
                    Shutdown.getInstance().startTelnetShutdown(_cSocket.getInetAddress().getHostAddress(), val, false);
                } else if (_usrCommand.startsWith("garbage")) {
                    _print.println("Collecting garbage...");
                    System.gc();
                    _print.println("done");
//                } else if (_usrCommand.startsWith("restart")) {
//                    try {
//                        int val = Integer.parseInt(_usrCommand.substring(8));
//                        Shutdown.getInstance().startTelnetShutdown(_cSocket.getInetAddress().getHostAddress(), val, true);
//                        _print.println("Server Will Restart In " + val + " Seconds!");
//                        _print.println("Type \"abort\" To Abort Restart!");
//                    }
//                    catch (StringIndexOutOfBoundsException e) {
//                        _print.println("Please Enter * amount of seconds to restart!");
//                    }
//                    catch (Exception NumberFormatException) {
//                        _print.println("Numbers Only!");
//                    }
//                } else if (_usrCommand.startsWith("abort")) {
//                    Shutdown.getInstance().telnetAbort(_cSocket.getInetAddress().getHostAddress());
//                    _print.println("OK! - Shutdown/Restart Aborted.");
                } else if (_usrCommand.equals("quit")) {
                } else if (_usrCommand.equals("battleRooms")) {
                    List<AbstractBattle> battles = BattleManager.getInstance().getBattles();
                    _print.println("showing all battle[" + battles.size() + "]");
                    for (AbstractBattle battle : battles) {
                        FastMap<Long, BattlePlayer> members = battle.getBattleMembers();
                        int membersSize = members.size();
                        StringBuilder membersStr = new StringBuilder("members size[" + membersSize + "] {");
                        for (FastMap.Entry<Long, BattlePlayer> e2 = members.head(), end2 = members.tail(); (e2 = e2.getNext()) != end2;) {
                            AbstractPaperGameUser user = e2.getValue().getGameUser();
                            if (user != null) {
                                membersStr.append("[ID: ").append(user.getId()).append(",");
                                membersStr.append("Nick: ").append(user.getPlayer().getUsername()).append("],");
                            }
                        }
                        membersStr.append("}");
                        _print.println("Battle id[" + battle.getBattleOrderId() + "], " + membersStr.toString());
                    }
                } else if (_usrCommand.equals("users")) {
                    _print.println("Enter page number");
                    _print.flush();
                    int pageNum;
                    try {
                        pageNum = Integer.parseInt(_read.readLine());
                    } catch (NumberFormatException e) {
                        pageNum = 0;
                    }
                    FastMap<Long, AbstractPaperGameUser> members = UsersManager.getInstance().getAllPaperGameUsers();
                    _print.println("showing users[" + members.size() + "] page [" + pageNum + "]");
                    int indx = 0;
                    int pageSize = 40;
                    int startIndx = pageNum * pageSize;
                    for (FastMap.Entry<Long, AbstractPaperGameUser> e = members.head(), end = members.tail(); (e = e.getNext()) != end;) {
                        indx++;
                        if (indx >= startIndx && indx < startIndx + pageSize) {
                            AbstractPaperGameUser user = e.getValue();
                            _print.println("UserId[" + user.getId() + "], Nick[" + user.getPlayer().getUsername() +"]");
                        }
                    }
                } else if (_usrCommand.length() == 0) {
                    /* Do Nothing Again - Same reason as the quit part */
                }
                _print.println("------");
                _print.flush();
            }
            if (!_cSocket.isClosed()) {
                _print.println("Bye Bye!");
                _print.flush();
                _cSocket.close();
            }
            telnetOutput(5, "Connection from " + _cSocket.getInetAddress().getHostAddress() + " was closed by client.");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            telnetServer.removeSession(sessionId);
        }
    }

    public int getSessionId() {
        return sessionId;
    }

    public boolean isStarted() {
        return started;
    }
}
